#pragma once

#include "node.h"
#include "Token.h"

class Expression: public Node
{
public:
};

class ArithmeticExpression: public Expression
{
};

class ArithmeticVariableExpression: public ArithmeticExpression
{
public:
    ArithmeticVariableExpression(const Token & v)
        : _v(v)
    {
    }
private:
    const Token & _v;
};

class ArithmeticNumberExpression: public ArithmeticExpression
{
public:
    ArithmeticNumberExpression(const Token & v)
        : _v(v)
    {
    }
private:
    const Token & _v;
};

class ArithmeticStringExpression: public ArithmeticExpression
{
public:
    ArithmeticStringExpression(const Token & v)
        : _v(v)
    {
    }
private:
    const Token & _v;
};

class ArithmeticParenthesisExpression: public ArithmeticExpression
{
public:
    ArithmeticParenthesisExpression(const ArithmeticExpression * v)
        : _v(v)
    {
    }

    ~ArithmeticParenthesisExpression()
    {
        FreeAndNull(_v);
    }
private:
    const ArithmeticExpression * _v;
};

class AddExpression: public ArithmeticExpression
{
public:
    AddExpression(const ArithmeticExpression * lhs, const ArithmeticExpression * rhs)
        : _lhs(lhs), _rhs(rhs)
    {
    }
    ~AddExpression()
    {
        FreeAndNull(_lhs);
        FreeAndNull(_rhs);
    }
private:
    const ArithmeticExpression * _lhs;
    const ArithmeticExpression * _rhs;
};

class MinusExpression: public ArithmeticExpression
{
public:
    MinusExpression(const ArithmeticExpression * lhs, const ArithmeticExpression * rhs)
        : _lhs(lhs), _rhs(rhs)
    {
    }
    ~MinusExpression()
    {
        FreeAndNull(_lhs);
        FreeAndNull(_rhs);
    }
private:
    const ArithmeticExpression * _lhs;
    const ArithmeticExpression * _rhs;
};

class MultipleExpression: public ArithmeticExpression
{
public:
    MultipleExpression(const ArithmeticExpression * lhs, const ArithmeticExpression * rhs)
        : _lhs(lhs), _rhs(rhs)
    {
    }
    ~MultipleExpression()
    {
        FreeAndNull(_lhs);
        FreeAndNull(_rhs);
    }
private:
    const ArithmeticExpression * _lhs;
    const ArithmeticExpression * _rhs;
};

class DivideExpression: public ArithmeticExpression
{
public:
    DivideExpression(const ArithmeticExpression * lhs, const ArithmeticExpression * rhs)
        : _lhs(lhs), _rhs(rhs)
    {
    }
    ~DivideExpression()
    {
        FreeAndNull(_lhs);
        FreeAndNull(_rhs);
    }
private:
    const ArithmeticExpression * _lhs;
    const ArithmeticExpression * _rhs;
};

class FunctionExpression: public ArithmeticExpression
{
public:
    FunctionExpression(const Token & name, std::vector<Expression *> * arguments)
        : _name(name), _arguments(arguments)
    {
    }
    ~FunctionExpression()
    {
        if (_arguments)
        {
            for (auto it=_arguments->begin(); it!= _arguments->end(); ++it)
            {
                if (*it) delete *it;
            }
            delete _arguments;
            _arguments = NULL;
        }
    }
private:
    const Token & _name;
    const std::vector<Expression *> * _arguments;
};

class BooleanExpression: public Expression
{
};

class BooleanParenthesisExpression: public BooleanExpression
{
public:
    BooleanParenthesisExpression(const BooleanExpression * v)
        : _v(v)
    {
    }

    ~BooleanParenthesisExpression()
    {
        FreeAndNull(_v);
    }
private:
    const BooleanExpression * _v;
};

class AndExpression: public BooleanExpression
{
public:
    AndExpression(const BooleanExpression * lhs, const BooleanExpression * rhs)
        : _lhs(lhs), _rhs(rhs)
    {
    }
    ~AndExpression()
    {
        FreeAndNull(_lhs);
        FreeAndNull(_rhs);
    }
private:
    const BooleanExpression * _lhs;
    const BooleanExpression * _rhs;
};

class OrExpression: public BooleanExpression
{
public:
    OrExpression(const BooleanExpression * lhs, const BooleanExpression * rhs)
        : _lhs(lhs), _rhs(rhs)
    {
    }
    ~OrExpression()
    {
        FreeAndNull(_lhs);
        FreeAndNull(_rhs);
    }
private:
    const BooleanExpression * _lhs;
    const BooleanExpression * _rhs;
};

class LessExpression: public BooleanExpression
{
public:
    LessExpression(const ArithmeticExpression * lhs, const ArithmeticExpression * rhs)
        : _lhs(lhs), _rhs(rhs)
    {
    }
    ~LessExpression()
    {
        FreeAndNull(_lhs);
        FreeAndNull(_rhs);
    }
private:
    const ArithmeticExpression * _lhs;
    const ArithmeticExpression * _rhs;
};

class GreaterExpression: public BooleanExpression
{
public:
    GreaterExpression(const ArithmeticExpression * lhs, const ArithmeticExpression * rhs)
        : _lhs(lhs), _rhs(rhs)
    {
    }
    ~GreaterExpression()
    {
        FreeAndNull(_lhs);
        FreeAndNull(_rhs);
    }
private:
    const ArithmeticExpression * _lhs;
    const ArithmeticExpression * _rhs;
};

class LessOrEqualExpression: public BooleanExpression
{
public:
    LessOrEqualExpression(const ArithmeticExpression * lhs, const ArithmeticExpression * rhs)
        : _lhs(lhs), _rhs(rhs)
    {
    }
    ~LessOrEqualExpression()
    {
        FreeAndNull(_lhs);
        FreeAndNull(_rhs);
    }
private:
    const ArithmeticExpression * _lhs;
    const ArithmeticExpression * _rhs;
};

class GreaterOrEqualExpression: public BooleanExpression
{
public:
    GreaterOrEqualExpression(const ArithmeticExpression * lhs, const ArithmeticExpression * rhs)
        : _lhs(lhs), _rhs(rhs)
    {
    }
    ~GreaterOrEqualExpression()
    {
        FreeAndNull(_lhs);
        FreeAndNull(_rhs);
    }
private:
    const ArithmeticExpression * _lhs;
    const ArithmeticExpression * _rhs;
};

class EqualExpression: public BooleanExpression
{
public:
    EqualExpression(const ArithmeticExpression * lhs, const ArithmeticExpression * rhs)
        : _lhs(lhs), _rhs(rhs)
    {
    }
    ~EqualExpression()
    {
        FreeAndNull(_lhs);
        FreeAndNull(_rhs);
    }
private:
    const ArithmeticExpression * _lhs;
    const ArithmeticExpression * _rhs;
};

class NotEqualExpression: public BooleanExpression
{
public:
    NotEqualExpression(const ArithmeticExpression * lhs, const ArithmeticExpression * rhs)
        : _lhs(lhs), _rhs(rhs)
    {
    }
    ~NotEqualExpression()
    {
        FreeAndNull(_lhs);
        FreeAndNull(_rhs);
    }
private:
    const ArithmeticExpression * _lhs;
    const ArithmeticExpression * _rhs;
};

class LikeExpression: public BooleanExpression
{
public:
    LikeExpression(const Token & varible, const Token & str)
        : _variable(varible), _str(str)
    {
    }
private:
    const Token & _variable;
    const Token & _str;
};

class ColumnExpression: public Node
{
public:
private:
};

class ColumnBooleanExpression:public ColumnExpression
{
public:
    ColumnBooleanExpression(const BooleanExpression * expression)
        : _expression(expression)
    {
    }

    ~ColumnBooleanExpression()
    {
        FreeAndNull(_expression);
    }
private:
    const Expression * _expression;
};

class ColumnArithmeticExpression:public ColumnExpression
{
public:
    ColumnArithmeticExpression(const ArithmeticExpression * expression)
        : _expression(expression)
    {
    }

    ~ColumnArithmeticExpression()
    {
        FreeAndNull(_expression);
    }
private:
    const Expression * _expression;
};

class CountExpression:public ColumnExpression
{
public:
    CountExpression(const ColumnExpression * expression)
        : _expression(expression)
    {
    }

    ~CountExpression()
    {
        FreeAndNull(_expression);
    }
private:
    const ColumnExpression * _expression;
};

class MaxExpression:public ColumnExpression
{
public:
    MaxExpression(const ColumnExpression * expression)
        : _expression(expression)
    {
    }

    ~MaxExpression()
    {
        FreeAndNull(_expression);
    }
private:
    const ColumnExpression * _expression;
};

class MinExpression:public ColumnExpression
{
public:
    MinExpression(const ColumnExpression * expression)
        : _expression(expression)
    {
    }

    ~MinExpression()
    {
        FreeAndNull(_expression);
    }
private:
    const ColumnExpression * _expression;
};